<script setup lang="ts">
import { ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import type { MenuVo, RouteMenu } from '@/type/Menu'
import { useMenuStore } from '@/stores/menu'
import type { ResultData } from '@/api/service'
import * as ElIcons from '@element-plus/icons-vue'
import { ElNotification } from 'element-plus'
import SInfo from '@/components/common/info/SInfo.vue'
import { menuInfoApi, menuListApi, saveMenuApi } from '@/api/menu'
import { useInfo } from '@/composables/info-composable'
import { PageQuery } from '@/type/common/list-types'
import type { Page } from '@/type/User'

const route = useRoute()
const router = useRouter()
const menuStore = useMenuStore()

const props = defineProps<{
  query: { menuId?: string }
}>()

const iconNames = Object.keys(ElIcons)
const iconDialogVisible = ref<boolean>(false)

const { statement, infoLoading, infoData, isNew, hiddenItem, showItem, validErrors } =
  useInfo<MenuVo>('MenuInfo', () => {
    if (props.query.menuId !== undefined) {
      infoLoading.value = true
      isNew.value = false
      menuInfoApi(props.query.menuId).then((response: ResultData<MenuVo>) => {
        // 触发菜单类型更改事件
        methods.menuTypeChange(response.data.menuType)
        infoLoading.value = false
        infoData.value = response.data
      })
    } else {
      // 新增菜单时设置的默认值
      // 排序默认为 1
      infoData.value.orderNum = 1
      // 菜单类型默认为菜单
      infoData.value.menuType = 'C'
      // 菜单状态默认为正常
      infoData.value.status = 0
      // 隐藏状态默认为显示
      infoData.value.visible = 0
    }
    // 初始化父菜单层级列表
    getParentId()
  })

const methods = {
  menuTypeChange: (menuType: String) => {
    infoData.value.component = null
    infoData.value.path = null
    // menuType 变更事件
    if (menuType === 'M') {
      // 针对目录，要清空并隐藏 component 和 path
      hiddenItem('component')
      hiddenItem('path')
    } else if (menuType === 'C') {
      showItem('component')
      showItem('path')
    } else if (menuType === 'F') {
      showItem('component')
      showItem('path')
      // 默认选中行内按钮
      infoData.value.path = 'top'
    }
  },
  save: () => {
    // 保存菜单
    saveMenuApi(infoData.value)
      .then(() => {
        ElNotification.success({
          title: '成功',
          message: '保存菜单成功',
          type: 'success'
        })
        // 执行返回方法
        methods.back()
      })
      .catch((err) => {
        if (err.code === 438) {
          validErrors(err.data)
        }
      })
  },
  back: () => {
    // 返回用户管理页面
    menuStore.closeTabOfPath(route.fullPath)
    router.push({ path: '/menu' })
  }
}

function changeIcon(icon: string) {
  infoData.value.icon = icon
  iconDialogVisible.value = false
}

const parentMenuList = ref<RouteMenu[]>()

function getParentId() {
  // 查询所有跟菜单 , infoParent 是和后端接口约定的特殊传递，传递后后端将不会在结果中包含 F 类型菜单
  const param: PageQuery = {
    pageNum: 1,
    pageSize: 1000,
    sortRules: [],
    filters: {}
  }
  menuListApi(param).then((response: ResultData<Page<RouteMenu[]>>) => {
    parentMenuList.value = response.data.modelList
    parentMenuList.value.unshift({ children: [], menuId: 'root', menuName: '根菜单' })
  })
}
</script>

<template>
  <s-info :data="infoData" :statement="statement" :methods="methods" :form-loading="infoLoading">
    <template #component="scope">
      <el-form-item
        :error="scope.mate.error"
        :required="scope.mate.required"
        :label="scope.formItem.menuType === 'F' ? '按钮事件' : '组件地址'"
      >
        <el-input v-model="scope.formItem.component" />
      </el-form-item>
    </template>
    <template #icon="scope">
      <el-form-item :label="scope.mate.label" :error="scope.mate.error">
        <el-icon color="#409eff" size="30" style="border: 1px solid #aaa; margin-right: 10px">
          <component :is="scope.formItem.icon" />
        </el-icon>
        <el-button @click="iconDialogVisible = true" size="small" text type="primary"
          >选择图标</el-button
        >
      </el-form-item>
    </template>
    <template #parentId="scope">
      <el-form-item :error="scope.mate.error" :required="scope.mate.required" label="父菜单">
        <el-cascader
          v-model="scope.formItem.parentId"
          :show-all-levels="false"
          :props="{ label: 'menuName', value: 'menuId', checkStrictly: true, emitPath: false }"
          :options="parentMenuList"
        />
      </el-form-item>
    </template>
    <template #path="scope">
      <el-form-item
        :error="scope.mate.error"
        :required="scope.mate.required"
        v-if="scope.formItem.menuType === 'F'"
        label="按钮类型"
      >
        <el-radio-group v-model="scope.formItem.path">
          <el-radio value="top">顶部</el-radio>
          <el-radio value="row">行内</el-radio>
        </el-radio-group>
      </el-form-item>
      <el-form-item
        :error="scope.mate.error"
        :required="scope.mate.required"
        v-else-if="scope.formItem.menuType === 'C'"
        label="路由地址"
      >
        <el-input v-model="scope.formItem.path" />
      </el-form-item>
    </template>
  </s-info>

  <el-dialog v-model="iconDialogVisible" title="选择菜单图标" width="900">
    <el-scrollbar height="600" style="padding: 0 15px">
      <ul class="s-icon-list">
        <li @click="changeIcon('')">无</li>
        <li
          @click="changeIcon(icon)"
          :class="{ active: infoData.icon === icon }"
          v-for="icon in iconNames"
          :key="icon"
        >
          <el-icon :color="infoData.icon === icon ? '#FFF' : ''" size="30">
            <component :is="icon" />
          </el-icon>
        </li>
        <li></li>
        <li></li>
      </ul>
    </el-scrollbar>
  </el-dialog>
</template>

<style scoped>
.s-icon-list {
  padding: 0;
  list-style: none;
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  border-right: 1px solid #dfdfe6;
  border-bottom: 1px solid #dfdfe6;
}

.s-icon-list li {
  height: 80px;
  display: flex;
  align-items: center;
  flex-direction: column;
  justify-content: center;
  border-left: 1px solid #dfdfe6;
  border-top: 1px solid #dfdfe6;
  cursor: pointer;
  transition: 0.1s;
}

.s-icon-list li.active {
  background-color: #409eff;
}
</style>
